package com.zf.nospring.rabbitmq.lazy;

import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.zf.nospring.rabbitmq.utils.RabbitUtils;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.concurrent.TimeoutException;

/**
 * 惰性队列，是rabbitmq3.6.0版本引入的
 * <p>
 * 默认情况下，普通的队列会把消息存储在内存中，这样做的主要目的是为了消息能尽快的发送给消费者。即使是持久化的消息，在被写入磁盘的同时也会在内存中驻留一份备份。
 * <p>
 * 惰性队列会将接收到的消息直接存入文件系统中，而不管是持久化的或者是非持久化的，这样可以减少了内存的消耗，但是会增加I/O的使用，
 * - 如果惰性队列中存储的消息是持久化的，那么rabbitmq重启后消息不会丢失。
 * - 如果惰性队列中存储的是非持久化的消息，那么rabbitmq重启之后消息一样会丢失。
 * <p>
 * 惰性队列中的消息存储在磁盘，只有在consumer要消费该消息时，才会加载到内存。
 * <p>
 * 一般当消费者由于各种各样的原因（比如消费者下线、宕机亦或者是由于维护而关闭等）而致使长时间内不能消费消息造成堆积时，惰性队列就很有必要了。
 * 他把消息直接存储到磁盘，不会写入内存，只有在consumer要消费该消息时，才会加载到内存。
 * <p>
 * 惰性队列+持久化消息 的组合可谓是最佳拍档
 */
public class LazyQueueProducer {
    public static void main(String[] args) throws IOException, TimeoutException {
        Connection connection = RabbitUtils.getDefaultConnection();
        Channel channel = connection.createChannel();

        HashMap<String, Object> queueArgs = new HashMap<>();
        // 声明队列为惰性队列时使用的参数
        queueArgs.put("x-queue-mode", "lazy");
        // 声明惰性队列
        String testLazyQueue = "test_lazy_queue";
        channel.queueDeclare(testLazyQueue, true, false, false, queueArgs);

        // 发非持久化消息，默认就是非持久化消息，rabbitmq重启后消息丢失
        for (int i = 0; i < 5; i++) {
            channel.basicPublish("", testLazyQueue, null, ("你好" + i).getBytes(StandardCharsets.UTF_8));
        }

        // 发送持久化消息, 设置参数：deliveryMode = 2 表示消息持久化，rabbitmq重启后消息依然存在，前提是队列是持久化的，否则存储消息的队列消失了，那么消息也就消失了
        AMQP.BasicProperties properties = new AMQP.BasicProperties.Builder()
                .deliveryMode(2)
                .build();
        for (int i = 0; i < 5; i++) {
            channel.basicPublish("", testLazyQueue, properties, ("持久化" + i).getBytes(StandardCharsets.UTF_8));
        }

        channel.close();
        connection.close();
    }
}
